package org.budo.graph.entity;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.budo.support.lang.util.NumberUtil;

import com.alibaba.druid.pool.DruidDataSource;

import lombok.Getter;
import lombok.Setter;

/**
 * @author li
 */
@Getter
@Setter
public class AppGraph {
    public static final String GRAPH_TYPE = "APP";

    private static final String JDBC_UPDATE_COUNT = "JdbcUpdateCount", RUNNING_COUNT = "RunningCount", JDBC_FETCH_ROW_COUNT = "JdbcFetchRowCount", //
            JDBC_EXECUTE_TIME_MILLIS = "JdbcExecuteTimeMillis", JDBC_EXECUTE_COUNT = "JdbcExecuteCount", REQUEST_COUNT = "RequestCount", THREAD_COUNT = "ThreadCount", //
            DRUID_POOLING_COUNT = "DruidPoolingCount", DRUID_NOT_EMPTY_WAIT_COUNT = "DruidNotEmptyWaitCount";

    public static final String[] TITLES = { REQUEST_COUNT, RUNNING_COUNT, JDBC_EXECUTE_COUNT, JDBC_EXECUTE_TIME_MILLIS, JDBC_FETCH_ROW_COUNT, //
            JDBC_UPDATE_COUNT, THREAD_COUNT, DRUID_POOLING_COUNT, DRUID_NOT_EMPTY_WAIT_COUNT };

    private Long requestCount;

    private Long jdbcExecuteCount;

    private Long jdbcExecuteTimeMillis;

    private Long jdbcFetchRowCount;

    private Long jdbcUpdateCount;

    private Long runningCount;

    private Long threadCount;

    private Long druidPoolingCount = 0L; // 池中连接数

    private Long druidNotEmptyWaitCount = 0L; // 等待次数

    public AppGraph(Map<String, Object> druidWebAppStat, List<DruidDataSource> druidDataSourceList) {
        Object requestCount = druidWebAppStat.get(REQUEST_COUNT);
        this.setRequestCount(NumberUtil.toLong(requestCount, 0L));

        Object jdbcExecuteCount = druidWebAppStat.get(JDBC_EXECUTE_COUNT);
        this.setJdbcExecuteCount(NumberUtil.toLong(jdbcExecuteCount, 0L));

        Object jdbcExecuteTimeMillis = druidWebAppStat.get(JDBC_EXECUTE_TIME_MILLIS);
        this.setJdbcExecuteTimeMillis(NumberUtil.toLong(jdbcExecuteTimeMillis, 0L));

        Object jdbcFetchRowCount = druidWebAppStat.get(JDBC_FETCH_ROW_COUNT);
        this.setJdbcFetchRowCount(NumberUtil.toLong(jdbcFetchRowCount, 0L));

        Object jdbcUpdateCount = druidWebAppStat.get(JDBC_UPDATE_COUNT);
        this.setJdbcUpdateCount(NumberUtil.toLong(jdbcUpdateCount, 0L));

        Object runningCount = druidWebAppStat.get(RUNNING_COUNT);
        this.setRunningCount(NumberUtil.toLong(runningCount, 0L));

        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        this.setThreadCount((long) threadMXBean.getThreadCount());

        if (null != druidDataSourceList && !druidDataSourceList.isEmpty()) {
            long poolingCount = 0L;
            long notEmptyWaitCount = 0L;

            for (DruidDataSource druidDataSource : druidDataSourceList) {
                String dbUrl = druidDataSource.getUrl();
                if (null == dbUrl || dbUrl.startsWith(" jdbc:redis://")) { // redis的跳过不记录，考虑另外专门做每一个数据源的曲线
                    continue;
                }

                poolingCount += druidDataSource.getPoolingCount();
                notEmptyWaitCount += druidDataSource.getNotEmptyWaitCount();
            }

            this.setDruidPoolingCount(poolingCount);
            this.setDruidNotEmptyWaitCount(notEmptyWaitCount);
        }
    }

    public Map<String, String> minus(AppGraph lastAppGraph) {
        Map<String, String> minusMap = new LinkedHashMap<String, String>(); // 这里应该是需要有序的Map的，顺序应该和 TITLES 一致
        minusMap.put(REQUEST_COUNT, (this.getRequestCount() - lastAppGraph.getRequestCount()) + ""); // 差值，增量
        minusMap.put(RUNNING_COUNT, this.getRunningCount() + ""); // 瞬时值，非增量
        minusMap.put(JDBC_EXECUTE_COUNT, (this.getJdbcExecuteCount() - lastAppGraph.getJdbcExecuteCount()) + ""); // 增量
        minusMap.put(JDBC_EXECUTE_TIME_MILLIS, (this.getJdbcExecuteTimeMillis() - lastAppGraph.getJdbcExecuteTimeMillis()) + "");// 增量
        minusMap.put(JDBC_FETCH_ROW_COUNT, (this.getJdbcFetchRowCount() - lastAppGraph.getJdbcFetchRowCount()) + "");// 增量
        minusMap.put(JDBC_UPDATE_COUNT, (this.getJdbcUpdateCount() - lastAppGraph.getJdbcUpdateCount()) + "");// 增量
        minusMap.put(THREAD_COUNT, this.getThreadCount() + ""); // 瞬时值，非增量

        minusMap.put(DRUID_POOLING_COUNT, this.getDruidPoolingCount() + ""); // 瞬时值，非增量
        minusMap.put(DRUID_NOT_EMPTY_WAIT_COUNT, (this.getDruidNotEmptyWaitCount() - lastAppGraph.getDruidNotEmptyWaitCount()) + ""); // 等待次数
        return minusMap;
    }
}